
/***********************************************
*   Project: Virtual Manufacturing System      *
*                                              *
*   Date: 03.08.12                             *
*                                              *
*   File: gmfParser.h                          *
* 					                           *
*   Author: Rafal Pielech                      *
*   E-mail: rafalpielech@hotmail.com           *
************************************************/


#ifndef GMFPARSER_H
#define GMFPARSER_H

#include <string>
using namespace std;
#include <utility.h>


template < class Real_type , class Integer_type > class gmfParser     // Pure virtual class declaration
{
     protected:
                  short             stateFlag;
                  Real_type      ** vertices;
                  Integer_type   ** faceIndices;
                  Integer_type      nofVertices , nofFaces;

                  void              clear( void );

     public:
                                        gmfParser( void );
                  virtual void          loadDataFile( const string fname ) = 0;
                         short          good( void );

                  pair< Real_type ** , Integer_type ** > getVertices_FaceIndices( void );
                  pair< Integer_type , Integer_type    > getNofVertices_Faces   ( void );
};


// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------


template < class Real_type , class Integer_type >
gmfParser< Real_type , Integer_type > :: gmfParser( void )
{
        vertices    = NULL;
        faceIndices = NULL;
        nofVertices = 0;
        nofFaces    = 0;
        stateFlag   = 1;
}

// --------------------------------------------------------------------------------

template < class Real_type , class Integer_type >
short
gmfParser< Real_type , Integer_type > :: good( void )
{
        return stateFlag;
}

// --------------------------------------------------------------------------------

template < class Real_type , class Integer_type >
pair< Real_type ** , Integer_type ** >
gmfParser< Real_type , Integer_type > :: getVertices_FaceIndices( void )
{
        pair< Real_type **, Integer_type ** > pointers( vertices , faceIndices );
        return pointers;
}

// --------------------------------------------------------------------------------

template < class Real_type , class Integer_type >
pair< Integer_type , Integer_type >
gmfParser< Real_type , Integer_type > :: getNofVertices_Faces( void )
{
        pair< Integer_type , Integer_type > values( nofVertices , nofFaces );
        return values;
}

// --------------------------------------------------------------------------------

template < class Real_type , class Integer_type >
void
gmfParser< Real_type , Integer_type > :: clear( void )
{
    Integer_type i;

        if( vertices != NULL )
        { 
            for( i = 0; i < nofVertices; i++ ) 
            {
                  if( vertices[ i ] != NULL )
                  {
                        delete [] vertices[ i ];
                        vertices[ i ] = NULL;
                  }
            }
                        
            delete [] vertices;
            vertices = NULL; 
        }
        
        if( faceIndices != NULL )
        {
            for( i = 0; i < nofVertices; i++ )
            {
                  if( faceIndices[ i ] != NULL )
                  {
                        delete [] faceIndices[ i ];  
                        faceIndices[ i ]  = NULL; 
                  }
            }
            
            delete [] faceIndices;
            faceIndices = NULL;
        }

      nofVertices = 0;
      nofFaces    = 0;
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


#include <fstream.h>

template < class Real_type , class Integer_type >
class gmfParser_tri : public gmfParser< Real_type , Integer_type >
{
        public:
                       gmfParser_tri( void ){}
                       gmfParser_tri( const string fname );

                  void loadDataFile( const string fname );
};

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template < class Real_type , class Integer_type >
gmfParser_tri< Real_type , Integer_type > :: gmfParser_tri( const string fname )
{
        loadDataFile( fname );
}

// ----------------------------------------------------------------------------

template < class Real_type , class Integer_type >
void
gmfParser_tri< Real_type , Integer_type > :: loadDataFile( const string fname )
{
// if previous call to this member function has been finished with success, nothing prevents user to load another file and
// overwrite prevoiusly allocated memory that's why clear() must be called first
// ---

   clear();

// ---
 
  short failure = 0 , success = 1;

    try
    {
          ifstream inputFile( fname.c_str() );
          if( !inputFile.good() ) throw( failure );   // ----- check if file properly opened --------------

          string label;
          inputFile >> label;

          if( !inputFile.good() ) throw( failure );
          else
          if( label.compare( "TRI" ) != 0 ) throw( failure );

          // -- extract number of vertices and indices from file --

           inputFile >> nofVertices;        // number of vertices

           if( !inputFile.good() ) throw( failure ); // failbit must be set because of bad data format in the stream or EOF

           inputFile >> nofFaces;           // number of faces

           if( !inputFile.good() ) throw( failure );

         // -------- if everything is OK then ... ----------------

          Integer_type Index_1 , Index_2;

          vertices = new Real_type * [ nofVertices ];
          
          for( Index_1 = 0; Index_1 < nofVertices; Index_1++ ) vertices[ Index_1 ] = NULL;
          // set all of them to NULL at start
          
          for( Index_1 = 0; Index_1 < nofVertices; Index_1++ ) vertices[ Index_1 ] = new Real_type [ 3 ];
          // each vertex has three floating-point coordinates

          for( Index_1 = 0; Index_1 < nofVertices; Index_1++ )
          {
              for( Index_2 = 0; Index_2 < 3; Index_2++ )
              {
                  inputFile >> vertices[ Index_1 ][ Index_2 ];
                  if( !inputFile.good() ) throw( failure ); // failbit must be set because of bad data format in the stream or EOF
              }
          }

         
          faceIndices = new Integer_type * [ nofFaces ];

          for( Index_1 = 0; Index_1 < nofFaces; Index_1++ ) faceIndices[ Index_1 ] = NULL;
          // set all of them to NULL at start


          for( Index_1 = 0; Index_1 < nofFaces; Index_1++ ) faceIndices[ Index_1 ] = new Integer_type [ 3 ];
          // in this case each face has three distinct indices
          
          
          for( Index_1 = 0; Index_1 < nofFaces; Index_1++ )
          {
              for( Index_2 = 0; Index_2 < 3; Index_2++ )
              {
                  inputFile >> faceIndices[ Index_1 ][ Index_2 ];
                  if( !inputFile.good() ) throw( failure ); // failbit must be set because of bad data format in the stream or EOF
              }
          }

       throw( success );  // EVERYTHING WENT OK !

    }
    catch( short exc )
    {
        stateFlag = exc;
        if( stateFlag == 0 ) clear();
    }
    catch( ... ) // std :: bad_alloc thrown by 'new' operator can be handled in here
    {
        stateFlag = 0;
        clear();
    }
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

template < class Real_type , class Integer_type >
class gmfParser_poly : public gmfParser< Real_type , Integer_type >
{
        public:
                       gmfParser_poly( void ){}
                       gmfParser_poly( const string fname );

                  void loadDataFile( const string fname );
};

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template < class Real_type , class Integer_type >
gmfParser_poly< Real_type , Integer_type > :: gmfParser_poly( const string fname )
{
        loadDataFile( fname );
}

// ----------------------------------------------------------------------------

template < class Real_type , class Integer_type >
void
gmfParser_poly< Real_type , Integer_type > :: loadDataFile( const string fname )
{
  
  clear();    
      
  short failure = 0 , success = 1;

    try
    {
          ifstream inputFile( fname.c_str() );
          if( !inputFile.good() ) throw( failure );   // ----- check if file properly opened --------------

          string label;
          inputFile >> label;

          if( !inputFile.good() ) throw( failure );
          else
          if( label.compare( "POLY" ) != 0 ) throw( failure );

         // -- extract number of vertices and indices from file --

            inputFile >> nofVertices; // number of vertices

            if( !inputFile.good() ) throw( failure ); // failbit must be set because of bad data format in the stream or EOF

            inputFile >> nofFaces; // number of faces

            if( !inputFile.good() ) throw( failure );

        // -------- if everything is OK then ... ----------------

          vertices = new Real_type * [ nofVertices ];
          // each vertex has three floating-point coordinates

          Integer_type Index_1 , Index_2;

          for( Index_1 = 0; Index_1 < nofVertices; Index_1++ ) vertices[ Index_1 ] = NULL;
          // set all of them to NULL at start
          
          for( Index_1 = 0; Index_1 < nofVertices; Index_1++ ) vertices[ Index_1 ] = new Real_type [ 3 ];
          // each vertex has three floating-point coordinates

          for( Index_1 = 0; Index_1 < nofVertices; Index_1++ )
          {
              for( Index_2 = 0; Index_2 < 3; Index_2++ )
              {
                  inputFile >> vertices[ Index_1 ][ Index_2 ];
                  if( !inputFile.good() ) throw( failure ); // failbit must be set because of bad data format in the stream or EOF
              }
          }

          // --------------------------------------------------------
          
          faceIndices = new Integer_type * [ nofFaces ];
          
          for( Index_1 = 0; Index_1 < nofFaces; Index_1++ ) faceIndices[ Index_1 ] = NULL;
          // set all of them to NULL at start
          
          Integer_type  fdescr;
          
          for( Index_1 = 0; Index_1 < nofFaces; Index_1++ )
          {
              inputFile >> fdescr;
              if( !inputFile.good() ) throw( failure );
              
              faceIndices[ Index_1 ] = new Integer_type [ 1 + fdescr ]; // fdescr of indices and face descriptor itself.

              faceIndices[ Index_1 ][ 0 ] = fdescr;              

              for( Index_2 = 0; Index_2 < fdescr; Index_2++ )
              {
                  inputFile >> faceIndices[ Index_1 ][ Index_2 + 1 ];
                  if( !inputFile.good() ) throw( failure );
              }
          }

       throw( success );  // EVERYTHING WENT OK !
    }
    catch( short exc )
    {
        stateFlag = exc;
        if( stateFlag == 0 ) clear();
    }
    catch( ... ) // std :: bad_alloc thrown by 'new' operator can be handled in here
    {
        stateFlag = 0;
        clear();
    }
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

#endif